package me.zhengjie.modules.system.utils.zf;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 3DES加密工具类
 * 工作模式：ECB
 * 填充方式：PKCS7
 * 密钥长度：32位
 * 输出格式：Base64
 *
 * @Author Let's go Lakers
 * @Date 2023/11/1
 **/
public class DESUtil {

    private static final String ALGORITHM = "DESede";
    private static final String TRANSFORMATION = "DESede/ECB/PKCS7Padding";
    private static final String CHARSET = "UTF-8";
    /**
     * 加密密钥
     */
    private static final String KEY = "3vQV2AhmUp999999ykKsDIDERkbRJKvd";
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 问题报错：java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding
     * java默认支持是PKCS5Padding填充方式
     * 目前Java要实现PKCS7Padding填充模式的加密，需要借助第三方Jar包才可以实现，就是在初始化的时候 Security.addProvider 增加第三方的提供者
     * 使用DES/ECB加密,加入下面的静态代码块来添加默认加密提供者即可
     */
    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    public static void main(String[] args) throws Exception {

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("TRANDATE", "20230906");
        paramMap.put("ACCTNO", "51820****0029348");
        paramMap.put("ACCTNONAME", "兰州市城关***");
        paramMap.put("JOURNO", "911005000024");

        String toJsonStr = JSONUtil.toJsonStr(paramMap);
        System.out.println(sdf.format(new Date()) + " 加密前报文：" + toJsonStr);
        String desEncryptECB = encrypt(toJsonStr);
        System.out.println(sdf.format(new Date()) + " 加密后报文：" + desEncryptECB);
        System.out.println(sdf.format(new Date()) + " 解密后报文：" + decrypt(desEncryptECB));

        String result = HttpUtil.post("https://114.255.114.***CHECK", desEncryptECB, 1500);
        System.out.println(sdf.format(new Date()) + " 返回结果：" + result);
        System.out.println("解密后结果：" + decrypt(result));
    }

    // 加密
    public static String encrypt(String plainText) throws Exception {
        byte[] keyBytes = KEY.getBytes(CHARSET);
        DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey secretKey = keyFactory.generateSecret(spec);

        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(CHARSET));
        return Base64.encodeBase64String(encryptedBytes);
    }

    // 解密
    public static String decrypt(String encryptedText) throws Exception {
        byte[] keyBytes = KEY.getBytes(CHARSET);
        DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey secretKey = keyFactory.generateSecret(spec);

        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        byte[] encryptedBytes = Base64.decodeBase64(encryptedText);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, CHARSET);
    }

    public static String signByMap(SortedMap<String, Object> data, String aesKey) {
        StringBuilder sign = new StringBuilder();
        if (data != null && !data.isEmpty()) {
            // 使用 TreeMap 对 map 按键进行排序
            Map<String, Object> sortedData = new TreeMap<>(data);
            for (Map.Entry<String, Object> entry : sortedData.entrySet()) {
//                System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
                if (entry.getValue() != null && ObjectUtil.notEqual(entry.getKey(), "imgList")) {
                    sign.append(entry.getValue());
                }
            }
        }
        if (sign.length() > 0) {
            sign = new StringBuilder(md5(aesKey + sign));
        }
        return sign.toString();
    }

    // 你的 md5 方法实现
    private static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));

            // 将字节数组转换为十六进制字符串
            StringBuilder result = new StringBuilder();
            for (byte b : hashBytes) {
                result.append(String.format("%02x", b));
            }

            return result.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }


}
